<template>
  <div ref="container" class="fireworks-container" v-show="visible">
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch,nextTick } from "vue";
import * as THREE from "three";

let audioContext: AudioContext | null = null;
let gainNode: GainNode | null = null;
let fireworkBuffer: AudioBuffer | null = null;
const activeAudioSources: AudioBufferSourceNode[] = [];

const props = defineProps({
  autoStart: { type: Boolean, default: false },
  particleCount: { type: Number, default: 300 },
  frequency: { type: Number, default: 0.05 },
  fadeDuration: { type: Number, default: 10 }
});

const emit = defineEmits(["animation-start", "animation-stop", "timeout"]);

const container = ref(null);
const isAnimating = ref(false);
let scene, camera, renderer, clock;
let fireworks = [];
let animationId = null;
let timeoutId = null;
const visible = ref(false);
const opacity = ref(0); // 控制整体透明度
let fadeInterval = null

// 爆炸形状定义
const EXPLOSION_TYPES = {
  SPHERE: {
    name: "sphere",
    createVelocity: (i, count) => {
      const angle1 = Math.random() * Math.PI * 2;
      const angle2 = Math.random() * Math.PI;
      const speed = 6 + Math.random() * 4;
      return new THREE.Vector3(
        Math.sin(angle1) * Math.cos(angle2) * speed,
        Math.sin(angle2) * speed,
        Math.cos(angle1) * Math.cos(angle2) * speed
      );
    },
  },
  STAR: {
    name: "star",
    createVelocity: (i, count) => {
      const spikes = 5;
      const angle = (i / count) * Math.PI * 2;
      const radius = i % 2 === 0 ? 8 : 4;
      return new THREE.Vector3(
        Math.cos(angle) * radius,
        Math.sin(angle) * radius,
        (Math.random() - 0.5) * 3
      ).multiplyScalar(0.8 + Math.random() * 0.4);
    },
  },
  HEART: {
    name: "heart",
    createVelocity: (i, count) => {
      const t = (i / count) * Math.PI * 2;
      return new THREE.Vector3(
        16 * Math.pow(Math.sin(t), 3),
        13 * Math.cos(t) -
          5 * Math.cos(2 * t) -
          2 * Math.cos(3 * t) -
          Math.cos(4 * t),
        (Math.random() - 0.5) * 2
      ).multiplyScalar(0.3);
    },
  },
  RING: {
    name: "ring",
    createVelocity: (i, count) => {
      const angle = (i / count) * Math.PI * 2;
      return new THREE.Vector3(
        Math.cos(angle) * 7,
        Math.abs(Math.sin(angle)) * 3,
        (Math.random() - 0.5) * 2
      );
    },
  },
};

// 明亮颜色预设
const COLORS = [
  new THREE.Color(1, 0.2, 0.2), // 亮红
  new THREE.Color(0.2, 1, 0.2), // 亮绿
  new THREE.Color(0.2, 0.5, 1), // 亮蓝
  new THREE.Color(1, 1, 0.2), // 亮黄
  new THREE.Color(1, 0.3, 1), // 亮紫
  new THREE.Color(0.2, 1, 1), // 亮青
];

class Firework {
  constructor() {
    this.shape = Object.values(EXPLOSION_TYPES)[Math.floor(Math.random() * 4)];
    this.color = COLORS[Math.floor(Math.random() * COLORS.length)];
    this.exploded = false;
    this.trail = [];

    // 创建发射火箭
    this.rocket = this.createRocket();
    this.rocket.position.set(
      (Math.random() - 0.5) * 30,
      -15,
      (Math.random() - 0.5) * 10
    );

    // 初始速度
    this.velocity = new THREE.Vector3(
      (Math.random() - 0.5) * 2,
      Math.random() * 5 + 20,
      (Math.random() - 0.5) * 2
    );

    scene.add(this.rocket);
  }

  createRocket() {
    const geometry = new THREE.SphereGeometry(0.4, 8, 8);
    const material = new THREE.MeshBasicMaterial({
      color: this.color,
      transparent: true,
      opacity: 0.9,
    });
    return new THREE.Mesh(geometry, material);
  }

  update(delta) {
    if (!this.exploded) {
      // 火箭上升
      this.rocket.position.add(this.velocity.clone().multiplyScalar(delta));
      this.velocity.y -= 12 * delta; // 重力减速

      // 添加尾迹
      if (Math.random() < 0.4) {
        this.addTrail();
      }

      // 到达顶点时爆炸
      if (this.velocity.y < 0) {
        this.explode();
      }
      return true;
    }

    // 更新爆炸粒子
    this.updateParticles(delta);
    this.updateTrail(delta);

    return this.particles?.length > 0 || this.trail.length > 0;
  }

  addTrail() {
    const geometry = new THREE.SphereGeometry(0.15, 6, 6);
    const material = new THREE.MeshBasicMaterial({
      color: this.color,
      transparent: true,
      opacity: 0.7,
    });
    const trail = new THREE.Mesh(geometry, material);
    trail.position.copy(this.rocket.position);

    trail.userData = { life: 0.6, maxLife: 0.6 };
    this.trail.push(trail);
    scene.add(trail);
  }

  explode() {
    this.exploded = true;
    const pos = this.rocket.position.clone();
    scene.remove(this.rocket);

    // 创建爆炸粒子
    this.createExplosionParticles(pos);
    this.createExplosionFlash(pos);
  }

  createExplosionParticles(position) {
    const count = Math.floor(props.particleCount * (0.7 + Math.random() * 0.6));
    this.particles = [];
    const texture = createParticleTexture();

    for (let i = 0; i < count; i++) {
      const material = new THREE.SpriteMaterial({
        map: texture,
        color: this.color,
        transparent: true,
        opacity: 1,
        blending: THREE.AdditiveBlending,
        sizeAttenuation: true,
      });

      const particle = new THREE.Sprite(material);
      particle.scale.set(0.7, 0.7, 1);

      particle.userData = {
        velocity: this.shape.createVelocity(i, count),
        life: 2 + Math.random(),
        maxLife: 0,
      };
      particle.userData.maxLife = particle.userData.life;
      particle.position.copy(position);

      this.particles.push(particle);
      scene.add(particle);
    }
  }

  createExplosionFlash(position) {
    const geometry = new THREE.SphereGeometry(1, 16, 16);
    const material = new THREE.MeshBasicMaterial({
      color: this.color,
      transparent: true,
      opacity: 0.9,
    });
    const flash = new THREE.Mesh(geometry, material);
    flash.position.copy(position);

    flash.userData = {
      velocity: new THREE.Vector3(),
      life: 0.3,
      maxLife: 0.3,
      maxSize: 4 + Math.random() * 3,
    };

    this.particles.push(flash);
    scene.add(flash);
  }

  updateParticles(delta) {
    for (let i = this.particles.length - 1; i >= 0; i--) {
      const p = this.particles[i];
      p.userData.life -= delta;

      if (p.userData.life <= 0) {
        scene.remove(p);
        this.particles.splice(i, 1);
        continue;
      }

      // 更新位置
      p.position.add(p.userData.velocity.clone().multiplyScalar(delta));

      // 重力影响
      p.userData.velocity.y -= 9.8 * delta * 0.5;

      // 更新视觉效果
      const lifeRatio = p.userData.life / p.userData.maxLife;
      p.material.opacity = lifeRatio;

      // 闪光特效缩放
      if (p.userData.maxSize) {
        const scale = p.userData.maxSize * (1 - lifeRatio);
        p.scale.set(scale, scale, scale);
      } else {
        p.scale.setScalar(lifeRatio * 0.7);
      }
    }
  }

  updateTrail(delta) {
    for (let i = this.trail.length - 1; i >= 0; i--) {
      const t = this.trail[i];
      t.userData.life -= delta;

      if (t.userData.life <= 0) {
        scene.remove(t);
        this.trail.splice(i, 1);
        continue;
      }

      t.material.opacity = t.userData.life / t.userData.maxLife;
    }
  }
}

async function initAudio() {
  try {
    audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
    gainNode = audioContext.createGain();
    gainNode.gain.value = 0.5; // Set volume
    gainNode.connect(audioContext.destination);
    
    // Load your audio file - replace with your actual audio file path
    const response = await fetch('/sounds/fireworks.wav');
    const arrayBuffer = await response.arrayBuffer();
    fireworkBuffer = await audioContext.decodeAudioData(arrayBuffer);
  } catch (e) {
    console.error("Audio initialization failed:", e);
  }
}



function playFireworkSound() {
    if (!audioContext || !fireworkBuffer || activeAudioSources.length>0) return;
  
  try {
    const source = audioContext.createBufferSource();
    source.buffer = fireworkBuffer;
    source.connect(gainNode!);
    source.loop = true;
    source.loopStart = 0;
    source.loopEnd = 5; 
    
    // Add to active sources for cleanup
    activeAudioSources.push(source);
    
    // Remove after playback finishes
    source.onended = () => {
      const index = activeAudioSources.indexOf(source);
      if (index > -1) {
        activeAudioSources.splice(index, 1);
      }
    };
    
    source.start(audioContext.currentTime);
  } catch (e) {
    console.error("Audio playback error:", e);
  }
}

function stopAllAudio() {
  // Stop all active audio sources immediately
  activeAudioSources.forEach(source => {
    try {
      source.stop();
      source.disconnect();
    } catch (e) {
      console.error("Error stopping audio source:", e);
    }
  });
  activeAudioSources.length = 0;
  
  // Close audio context if exists
  if (audioContext && audioContext.state !== 'closed') {
    audioContext.close().catch(e => console.error("Error closing audio context:", e));
  }
  audioContext = null;
}


function createParticleTexture() {
  const canvas = document.createElement("canvas");
  canvas.width = canvas.height = 64;
  const ctx = canvas.getContext("2d");

  const gradient = ctx.createRadialGradient(32, 32, 0, 32, 32, 32);
  gradient.addColorStop(0, "rgba(255,255,255,1)");
  gradient.addColorStop(0.2, "rgba(255,255,255,0.9)");
  gradient.addColorStop(1, "rgba(255,255,255,0)");

  ctx.fillStyle = gradient;
  ctx.beginPath();
  ctx.arc(32, 32, 32, 0, Math.PI * 2);
  ctx.fill();

  const texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;
  return texture;
}

function initThreeJS() {
  if (!container.value) return;
  scene = new THREE.Scene();
  scene.background = props.transparentBackground
    ? null
    : new THREE.Color(0x080820);

  camera = new THREE.PerspectiveCamera(
    60,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.position.set(0, 0, 50);
  camera.lookAt(0, 5, 0); // 稍微向上看

  renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: 0.6,
    powerPreference: "high-performance",
  });
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  container.value.appendChild(renderer.domElement);

  createStarfield();
  createGround();
}

function createStarfield() {
  const geometry = new THREE.BufferGeometry();
  const material = new THREE.PointsMaterial({
    color: 0xffffff,
    size: 0.15,
    transparent: true,
  });

  const vertices = [];
  for (let i = 0; i < 1000; i++) {
    vertices.push(
      (Math.random() - 0.5) * 2000,
      (Math.random() - 0.5) * 2000,
      (Math.random() - 0.5) * 2000
    );
  }

  geometry.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(vertices, 3)
  );
  scene.add(new THREE.Points(geometry, material));
}

function createGround() {
  const geometry = new THREE.PlaneGeometry(100, 100);
  const material = new THREE.MeshBasicMaterial({
    color: 0x333344,
    side: THREE.DoubleSide,
    transparent: true,
    opacity: 0.3,
  });
  const ground = new THREE.Mesh(geometry, material);
  ground.rotation.x = -Math.PI / 2;
  ground.position.y = -15;
  scene.add(ground);
}

function animate() {
    playFireworkSound();
  animationId = requestAnimationFrame(animate);
  const delta = Math.min(clock.getDelta(), 0.1); // 限制最大delta

  // 随机发射新烟花
  if (Math.random() < props.frequency) {
    fireworks.push(new Firework());
  }

  // 更新所有烟花
  for (let i = fireworks.length - 1; i >= 0; i--) {
    if (!fireworks[i].update(delta)) {
      fireworks.splice(i, 1);
    }
  }

  renderer.render(scene, camera);
}

function startAnimation() {
  console.log('Starting animation with visibility:', visible.value); // 调试日志
  
  if (!audioContext) {
    initAudio();
  }

  // 强制显示容器
  visible.value = true;
  
  // 确保DOM更新完成
  nextTick(() => {
    if (!container.value) {
      console.error('Container element not found');
      return;
    }

    // 清除可能存在的旧渲染器
    if (renderer) {
      renderer.dispose();
      if (container.value.contains(renderer.domElement)) {
        container.value.removeChild(renderer.domElement);
      }
    }

    // 初始化Three.js
    initThreeJS();
    
    // 确保渲染器已创建
    if (!renderer) {
      console.error('Renderer creation failed');
      return;
    }

    // 强制添加渲染器DOM
    if (!container.value.contains(renderer.domElement)) {
      container.value.appendChild(renderer.domElement);
      console.log('Renderer DOM added');
    }

    // 开始动画
    isAnimating.value = true;
    clock = new THREE.Clock();
    animate();

    setTimeout(() => {
        stopAnimation();
    }, props.fadeDuration*1000);
  });
}

function stopAnimation() {
  if (!isAnimating.value) return;

  cancelAnimationFrame(animationId);
  clearTimeout(timeoutId);
  clearInterval(fadeInterval);
  isAnimating.value = false;

  stopAllAudio();

  // 清除所有烟花对象
  fireworks.forEach((fw) => {
    if (fw.rocket) scene.remove(fw.rocket);
    fw.particles?.forEach((p) => scene.remove(p));
    fw.trail.forEach((t) => scene.remove(t));
  });
  fireworks = [];

  // 重置透明度
  opacity.value = 0;
  emit("animation-stop");
  visible.value = false;
}

function cleanup() {
  stopAnimation();
  clearTimeout(timeoutId);
  window.removeEventListener("resize", handleResize);
  if (renderer) {
    renderer.dispose();
    if (container.value?.contains(renderer.domElement)) {
      container.value.removeChild(renderer.domElement);
    }
  }
}

function handleResize() {
  camera.aspect = container.value.clientWidth / container.value.clientHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(container.value.clientWidth, container.value.clientHeight);
}

onMounted(() => {
  window.addEventListener("resize", handleResize);
});

onUnmounted(() => {
  stopAnimation();
  stopAllAudio();
  window.removeEventListener("resize", handleResize);
  if (renderer) {
    renderer.dispose();
    if (container.value?.contains(renderer.domElement)) {
      container.value.removeChild(renderer.domElement);
    }
  }
});

defineExpose({
  startAnimation,
  stopAnimation,
  isAnimating,
  visible,
});
</script>

<style scoped>
.fireworks-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;  /* 使用视口单位 */
    height: 100vh;
    z-index: 99999; /* 更高层级 */
    pointer-events: none; /* 防止阻挡交互 */
  }
</style>
